<template>
	<view
		class="v-loading-icon"
		:style="[$u.addStyle(customStyle)]"
		:class="[vertical && 'v-loading-icon--vertical']"
		v-if="show"
	>
		<view
			v-if="!webviewHide"
			class="v-loading-icon__spinner"
			:class="[`v-loading-icon__spinner--${mode}`]"
			ref="ani"
			:style="{
				color: color,
				width: $u.addUnit(size),
				height: $u.addUnit(size),
				borderTopColor: color,
				borderBottomColor: otherBorderColor,
				borderLeftColor: otherBorderColor,
				borderRightColor: otherBorderColor,
				'animation-duration': `${duration}ms`,
				'animation-timing-function':
					mode === 'semicircle' || mode === 'circle'
						? timingFunction
						: '',
			}"
		>
			<block v-if="mode === 'spinner'">
				<!-- #ifndef APP-NVUE -->
				<view
					v-for="(item, index) in array12"
					:key="index"
					class="v-loading-icon__dot"
				>
				</view>
				<!-- #endif -->
				<!-- #ifdef APP-NVUE -->
				<!-- 此组件内部图标部分无法设置宽高，即使通过width和height配置了也无效 -->
				<loading-indicator
					v-if="!webviewHide"
					class="v-loading-indicator"
					:animating="true"
					:style="{
						color: color,
						width: $u.addUnit(size),
						height: $u.addUnit(size),
					}"
				/>
				<!-- #endif -->
			</block>
		</view>
		<text
			v-if="text"
			class="v-loading-icon__text"
			:style="{
				fontSize: $u.addUnit(textSize),
				color: textColor,
			}"
			>{{ text }}</text
		>
	</view>
</template>

<script>
import props from "./props.js";
import mpMixin from "../../libs/mixin/mpMixin.js";
import mixin from "../../libs/mixin/mixin.js";
// #ifdef APP-NVUE
const animation = weex.requireModule("animation");
// #endif
/**
 * loading 加载动画
 * @description 警此组件为一个小动画，目前用在vcu-uni-view的loadmore加载更多和switch开关等组件的正在加载状态场景。
 * @property {Boolean}			show			是否显示组件  (默认 true)
 * @property {String}			color			动画活动区域的颜色，只对 mode = flower 模式有效（默认color['v-tips-color']）
 * @property {String}			textColor		提示文本的颜色（默认color['v-tips-color']）
 * @property {Boolean}			vertical		文字和图标是否垂直排列 (默认 false )
 * @property {String}			mode			模式选择，见官网说明（默认 'circle' ）
 * @property {String | Number}	size			加载图标的大小，单位px （默认 24 ）
 * @property {String | Number}	textSize		文字大小（默认 15 ）
 * @property {String | Number}	text			文字内容
 * @property {String}			timingFunction	动画模式 （默认 'ease-in-out' ）
 * @property {String | Number}	duration		动画执行周期时间（默认 1200）
 * @property {String}			inactiveColor	mode=circle时的暗边颜色
 * @property {Object}			customStyle		定义需要用到的外部样式
 * @example <v-loading mode="circle"></v-loading>
 */
export default {
	name: "v-loading-icon",
	mixins: [mpMixin, mixin, props],
	data() {
		return {
			// Array.form可以通过一个伪数组对象创建指定长度的数组
			// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from
			array12: Array.from({
				length: 12,
			}),
			// 这里需要设置默认值为360，否则在安卓nvue上，会延迟一个duration周期后才执行
			// 在iOS nvue上，则会一开始默认执行两个周期的动画
			aniAngel: 360, // 动画旋转角度
			webviewHide: false, // 监听webview的状态，如果隐藏了页面，则停止动画，以免性能消耗
			loading: false, // 是否运行中，针对nvue使用
		};
	},
	computed: {
		// 当为circle类型时，给其另外三边设置一个更轻一些的颜色
		// 之所以需要这么做的原因是，比如父组件传了color为红色，那么需要另外的三个边为浅红色
		// 而不能是固定的某一个其他颜色(因为这个固定的颜色可能浅蓝，导致效果没有那么细腻良好)
		otherBorderColor() {
			const lightColor = uni.$u.colorGradient(
				this.color,
				"#ffffff",
				100
			)[80];
			if (this.mode === "circle") {
				return this.inactiveColor ? this.inactiveColor : lightColor;
			} else {
				return "transparent";
			}
			// return this.mode === 'circle' ? this.inactiveColor ? this.inactiveColor : lightColor : 'transparent'
		},
	},
	watch: {
		show(n) {
			// nvue中，show为true，且为非loading状态，就重新执行动画模块
			// #ifdef APP-NVUE
			if (n && !this.loading) {
				setTimeout(() => {
					this.startAnimate();
				}, 30);
			}
			// #endif
		},
	},
	mounted() {
		this.init();
	},
	methods: {
		init() {
			setTimeout(() => {
				// #ifdef APP-NVUE
				this.show && this.nvueAnimate();
				// #endif
				// #ifdef APP-PLUS
				this.show && this.addEventListenerToWebview();
				// #endif
			}, 20);
		},
		// 监听webview的显示与隐藏
		addEventListenerToWebview() {
			// webview的堆栈
			const pages = getCurrentPages();
			// 当前页面
			const page = pages[pages.length - 1];
			// 当前页面的webview实例
			const currentWebview = page.$getAppWebview();
			// 监听webview的显示与隐藏，从而停止或者开始动画(为了性能)
			currentWebview.addEventListener("hide", () => {
				this.webviewHide = true;
			});
			currentWebview.addEventListener("show", () => {
				this.webviewHide = false;
			});
		},
		// #ifdef APP-NVUE
		nvueAnimate() {
			// nvue下，非spinner类型时才需要旋转，因为nvue的spinner类型，使用了weex的
			// loading-indicator组件，自带旋转功能
			this.mode !== "spinner" && this.startAnimate();
		},
		// 执行nvue的animate模块动画
		startAnimate() {
			this.loading = true;
			const ani = this.$refs.ani;
			if (!ani) return;
			animation.transition(
				ani,
				{
					// 进行角度旋转
					styles: {
						transform: `rotate(${this.aniAngel}deg)`,
						transformOrigin: "center center",
					},
					duration: this.duration,
					timingFunction: this.timingFunction,
					// delay: 10
				},
				() => {
					// 每次增加360deg，为了让其重新旋转一周
					this.aniAngel += 360;
					// 动画结束后，继续循环执行动画，需要同时判断webviewHide变量
					// nvue安卓，页面隐藏后依然会继续执行startAnimate方法
					this.show && !this.webviewHide
						? this.startAnimate()
						: (this.loading = false);
				}
			);
		},
		// #endif
	},
};
</script>

<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$v-loading-icon-color: #c8c9cc !default;
$v-loading-icon-text-margin-left: 4px !default;
$v-loading-icon-text-color: $v-content-color !default;
$v-loading-icon-text-font-size: 14px !default;
$v-loading-icon-text-line-height: 20px !default;
$v-loading-width: 30px !default;
$v-loading-height: 30px !default;
$v-loading-max-width: 100% !default;
$v-loading-max-height: 100% !default;
$v-loading-semicircle-border-width: 2px !default;
$v-loading-semicircle-border-color: transparent !default;
$v-loading-semicircle-border-top-right-radius: 100px !default;
$v-loading-semicircle-border-top-left-radius: 100px !default;
$v-loading-semicircle-border-bottom-left-radius: 100px !default;
$v-loading-semicircle-border-bottom-right-radiu: 100px !default;
$v-loading-semicircle-border-style: solid !default;
$v-loading-circle-border-top-right-radius: 100px !default;
$v-loading-circle-border-top-left-radius: 100px !default;
$v-loading-circle-border-bottom-left-radius: 100px !default;
$v-loading-circle-border-bottom-right-radiu: 100px !default;
$v-loading-circle-border-width: 2px !default;
$v-loading-circle-border-top-color: #e5e5e5 !default;
$v-loading-circle-border-right-color: $v-loading-circle-border-top-color !default;
$v-loading-circle-border-bottom-color: $v-loading-circle-border-top-color !default;
$v-loading-circle-border-left-color: $v-loading-circle-border-top-color !default;
$v-loading-circle-border-style: solid !default;
$v-loading-icon-host-font-size: 0px !default;
$v-loading-icon-host-line-height: 1 !default;
$v-loading-icon-vertical-margin: 6px 0 0 !default;
$v-loading-icon-dot-top: 0 !default;
$v-loading-icon-dot-left: 0 !default;
$v-loading-icon-dot-width: 100% !default;
$v-loading-icon-dot-height: 100% !default;
$v-loading-icon-dot-before-width: 2px !default;
$v-loading-icon-dot-before-height: 25% !default;
$v-loading-icon-dot-before-margin: 0 auto !default;
$v-loading-icon-dot-before-background-color: currentColor !default;
$v-loading-icon-dot-before-border-radius: 40% !default;

.v-loading-icon {
	/* #ifndef APP-NVUE */
	// display: inline-flex;
	/* #endif */
	flex-direction: row;
	align-items: center;
	justify-content: center;
	color: $v-loading-icon-color;

	&__text {
		margin-left: $v-loading-icon-text-margin-left;
		color: $v-loading-icon-text-color;
		font-size: $v-loading-icon-text-font-size;
		line-height: $v-loading-icon-text-line-height;
	}

	&__spinner {
		width: $v-loading-width;
		height: $v-loading-height;
		position: relative;
		/* #ifndef APP-NVUE */
		box-sizing: border-box;
		max-width: $v-loading-max-width;
		max-height: $v-loading-max-height;
		animation: v-rotate 1s linear infinite;
		/* #endif */
	}

	&__spinner--semicircle {
		border-width: $v-loading-semicircle-border-width;
		border-color: $v-loading-semicircle-border-color;
		border-top-right-radius: $v-loading-semicircle-border-top-right-radius;
		border-top-left-radius: $v-loading-semicircle-border-top-left-radius;
		border-bottom-left-radius: $v-loading-semicircle-border-bottom-left-radius;
		border-bottom-right-radius: $v-loading-semicircle-border-bottom-right-radiu;
		border-style: $v-loading-semicircle-border-style;
	}

	&__spinner--circle {
		border-top-right-radius: $v-loading-circle-border-top-right-radius;
		border-top-left-radius: $v-loading-circle-border-top-left-radius;
		border-bottom-left-radius: $v-loading-circle-border-bottom-left-radius;
		border-bottom-right-radius: $v-loading-circle-border-bottom-right-radiu;
		border-width: $v-loading-circle-border-width;
		border-top-color: $v-loading-circle-border-top-color;
		border-right-color: $v-loading-circle-border-right-color;
		border-bottom-color: $v-loading-circle-border-bottom-color;
		border-left-color: $v-loading-circle-border-left-color;
		border-style: $v-loading-circle-border-style;
	}

	&--vertical {
		flex-direction: column;
	}
}

/* #ifndef APP-NVUE */
:host {
	font-size: $v-loading-icon-host-font-size;
	line-height: $v-loading-icon-host-line-height;
}

.v-loading-icon {
	&__spinner--spinner {
		animation-timing-function: steps(12);
	}

	&__text:empty {
		display: none;
	}

	&--vertical &__text {
		margin: $v-loading-icon-vertical-margin;
		color: $v-content-color;
	}

	&__dot {
		position: absolute;
		top: $v-loading-icon-dot-top;
		left: $v-loading-icon-dot-left;
		width: $v-loading-icon-dot-width;
		height: $v-loading-icon-dot-height;

		&:before {
			display: block;
			width: $v-loading-icon-dot-before-width;
			height: $v-loading-icon-dot-before-height;
			margin: $v-loading-icon-dot-before-margin;
			background-color: $v-loading-icon-dot-before-background-color;
			border-radius: $v-loading-icon-dot-before-border-radius;
			content: " ";
		}
	}
}

@for $i from 1 through 12 {
	.v-loading-icon__dot:nth-of-type(#{$i}) {
		transform: rotate($i * 30deg);
		opacity: 1 - 0.0625 * ($i - 1);
	}
}

@keyframes v-rotate {
	0% {
		transform: rotate(0deg);
	}

	to {
		transform: rotate(1turn);
	}
}

/* #endif */
</style>
